package ${projectDomain}.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.unswift.annotation.api.Api;
import com.unswift.annotation.api.ApiEntity;
import com.unswift.annotation.api.ApiField;
import com.unswift.annotation.api.ApiMethod;
import com.unswift.cache.MemoryCache;
import ${projectDomain}.annotation.excel.Excel;
import ${projectDomain}.annotation.excel.ExcelColumn;
import ${projectDomain}.excel.IExcelTranslate;
import ${projectDomain}.utils.HttpUtils.UploadAffix;
import com.unswift.exception.CoreException;
import com.unswift.utils.ClassUtils;
import com.unswift.utils.DateUtils;
import com.unswift.utils.ExceptionUtils;
import com.unswift.utils.FileUtils;
import com.unswift.utils.NumberUtils;
import com.unswift.utils.ObjectUtils;
import com.unswift.utils.StringUtils;

import lombok.Data;

@Api(value="excel公共操作类型", author="unswift", date="2023-07-11", version="1.0.0")
public final class ExcelUtils {
	
	@ApiMethod(value="创建97-2003版的excel对象", returns = @ApiField("excel对象"))
	public static Workbook create2003Xls() {
		return new HSSFWorkbook();
	}
	
	@ApiMethod(value="创建2007版的excel对象", returns = @ApiField("excel对象"))
	public static Workbook create2007Xlsx() {
		return new XSSFWorkbook();
	}
	
	@ApiMethod(value="创建2007版低内存的excel对象", returns = @ApiField("excel对象"))
	public static Workbook createBig2007Xlsx() {
		return new SXSSFWorkbook();
	}
	
	@ApiMethod(value="根据文件路径加载excel对象", params = {@ApiField("文件路径")}, returns = @ApiField("excel对象"))
	public static Workbook load(String filePath) {
		return load(new File(filePath));
	}
	
	@ApiMethod(value="根据文件加载excel对象", params = {@ApiField("文件")}, returns = @ApiField("excel对象"))
	public static Workbook load(File file) {
		try {
			return load(new FileInputStream(file));
		} catch (CoreException e) {
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("loading.excel.error", e, e.getMessage());
		}
	}
	
	@ApiMethod(value="根据文件流加载excel对象", params = {@ApiField("文件流")}, returns = @ApiField("excel对象"))
	public static Workbook load(InputStream inputStream) {
		try {
			return new XSSFWorkbook(inputStream);
		} catch (CoreException e) {
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("loading.excel.error", e, e.getMessage());
		}
	}
	
	public static void writerFile(Workbook workbook, File file) {
		FileOutputStream output=null;
		try {
			FileUtils.createFile(file, true);
			output=new FileOutputStream(file);
			workbook.write(output);
			output.flush();
		} catch (Exception e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("excel.export.writer.file.error", e, e.getMessage());
		} finally {
			close(workbook);
			FileUtils.close(output);
		}
	}
	
	public static String writerHttp(Workbook workbook, String url, String streamName, String fileName, Map<String, String> params, Map<String, String> header) {
		ByteArrayOutputStream output=null;
		try {
			output=new ByteArrayOutputStream();
			workbook.write(output);
			output.flush();
		} catch (Exception e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("excel.export.writer.file.error", e, e.getMessage());
		} finally {
			close(workbook);
		}
		try {
			HttpUtils httpUtils=BeanUtils.getBean(HttpUtils.class);
			Map<String, Object> fileParam=new HashMap<String, Object>();
			fileParam.put(streamName, new UploadAffix(fileName, new ByteArrayInputStream(output.toByteArray())));
			fileParam.putAll(params);
			return httpUtils.postFileToString(url, fileParam, header);
		} catch (Exception e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("excel.export.writer.file.error", e, e.getMessage());
		} finally {
			FileUtils.close(output);
		}
	}
	
	
	@ApiMethod(value="关闭excel对象", params = @ApiField("excel对象"))
	public static void close(Workbook workbook) {
		try {
			workbook.close();
			if(workbook instanceof SXSSFWorkbook) {
				((SXSSFWorkbook)workbook).dispose();
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("excel.close.exception", e, e.getMessage());
		}
	}
	
	@ApiMethod(value="创建Sheet对象", params = {@ApiField("excel对象"), @ApiField("sheet的名称")}, returns = @ApiField("excel的sheet对象"))
	public static Sheet createSheet(Workbook workbook, String sheetName) {
		return workbook.createSheet(sheetName);
	}
	
	/**
	 * @param <T>
	 * @param workbook
	 * @param sheet
	 * @param dataList
	 * @param excelModel
	 * @param startRow
	 * @return
	 */
	public static <T> int writerData(Workbook workbook, Sheet sheet, List<T> dataList, Class<?> excelModel, int startRow, String language) {
		Excel excelAnno=excelModel.getAnnotation(Excel.class);
		ExceptionUtils.empty(excelAnno, "excel.export.entity.must.excel.annotation", excelModel.getSimpleName());
		List<ExcelExportColumn> excelExportColumnList=getExportColumnList(excelModel);//导出列的列表
		if(startRow==0) {
			startRow=excelExportTitle(workbook, sheet, sheet.getSheetName(), excelAnno, excelExportColumnList);//生成表头
		}
		Row row;
		Cell cell;
		int columnLength=excelExportColumnList.size();
		ExcelColumn columnAnno;
		ExcelExportColumn columnConfig;
		Object value;
		String cellValue;
		IExcelTranslate excelTranslate;
		int width;
		for (T data : dataList) {
			row=sheet.createRow(startRow);
			row.setHeightInPoints(excelAnno.rowHeight());
			for (int i = 0; i < columnLength; i++) {
				cell=row.createCell(i);
				columnConfig=excelExportColumnList.get(i);
				value=ClassUtils.get(data, columnConfig.getFieldName());
				if(ObjectUtils.isEmpty(value)){
					cell.setCellValue("");
					continue;
				}
				columnAnno=columnConfig.getExcelColumn();
				if(ObjectUtils.isNotEmpty(columnAnno.format())){
					if(value instanceof Date){
						value=DateUtils.format((Date)value, columnAnno.format());
					}else if(value instanceof Number){
						value=NumberUtils.format((Number)value, columnAnno.format());
					}else{
						throw ExceptionUtils.message("excel.export.column.format.error", columnConfig.getFieldType().getSimpleName(), columnAnno.format(), startRow+1, i+1);
					}
				}
				if(ObjectUtils.isNotEmpty(columnAnno.translateBean())){
					excelTranslate=BeanUtils.getBean(columnAnno.translateBean());
					value=excelTranslate.translate(columnAnno.translateType(), language, value);
				}
				if(ObjectUtils.isEmpty(value)){
					cell.setCellValue("");
					continue;
				}
				cellValue=value.toString();
				cell.setCellValue(cellValue);
				if(columnConfig.getAutoWidth()){
					width=StringUtils.stringToWordLength(cellValue)+1;
					if(columnConfig.getWidth()<width && width<30){
						columnConfig.setWidth(width);
					}
				}
			}
			startRow++;
		}
		for (int i = 0; i < columnLength; i++) {
			width=sheet.getColumnWidth(i);
			if(excelExportColumnList.get(i).getWidth()!=width) {
				sheet.setColumnWidth(i, excelExportColumnList.get(i).getWidth()*256);
			}
		}
		if(sheet instanceof SXSSFSheet) {
			try {
				((SXSSFSheet)sheet).flushRows();//将数据刷新到临时文件
			} catch (Exception e) {
				e.printStackTrace();
				
			}
		}
		return startRow;
	}
	
	@ApiMethod(value="获取导出的Sheet,如果存在Excel注解，则使用Excel注解的value，否则使用ApiEntity注解的value", params=@ApiField("导出实体模板"), returns=@ApiField("excel的sheet名字"))
	public static String getSheetName(Class<?> excelModel){
		Excel excelAnno=excelModel.getAnnotation(Excel.class);
		ExceptionUtils.empty(excelAnno, "excel.export.entity.must.excel.annotation", excelModel.getSimpleName());
		String sheetName;
		if(ObjectUtils.isEmpty(excelAnno.value())){
			ApiEntity apiEntity=excelModel.getAnnotation(ApiEntity.class);
			if(ObjectUtils.isEmpty(apiEntity) || ObjectUtils.isEmpty(apiEntity.value())){
				sheetName="Sheet1";
			}else{
				sheetName=apiEntity.value().replace("导出实体", "");
			}
		}else{
			sheetName=excelAnno.value();
		}
		return sheetName;
	}
	
	@ApiMethod(value="获取导出的列对象集合", params=@ApiField("导出实体模板"), returns=@ApiField("列对象集合"))
	private static List<ExcelExportColumn> getExportColumnList(Class<?> excelModel){
		List<Field> fieldList=ClassUtils.getFieldList(excelModel).stream().filter(f -> ObjectUtils.isNotEmpty(f.getAnnotation(ExcelColumn.class))).collect(Collectors.toList());
		List<ExcelExportColumn> excelColumnList=new ArrayList<ExcelExportColumn>();
		ExcelExportColumn excelField;
		int order=1;
		for (Field field : fieldList) {
			excelField = new ExcelExportColumn(field.getName(), field.getType(), field.getAnnotation(ExcelColumn.class), field.getAnnotation(ApiField.class));
			if(excelField.getOrder()==-1){
				excelField.setOrder(order);
			}
			excelColumnList.add(excelField);
			order++;
		}
		excelColumnList=excelColumnList.stream().sorted(Comparator.comparing(ExcelExportColumn::getOrder)).collect(Collectors.toList());//根据order排序
		return excelColumnList;
	}
	
	@ApiMethod(value="生成Excel的标题及表头", params={@ApiField("Excel工作表"), @ApiField("Excel Sheet"), @ApiField("Excel标题名称"), @ApiField("Excel导出注解"), @ApiField("列说明")})
	private static int excelExportTitle(Workbook workbook, Sheet sheet, String excelTitle, Excel excelAnno, List<ExcelExportColumn> excelExportColumnList){
		int rowIndex=0;
		Row titleRow=sheet.createRow(rowIndex);
		titleRow.setHeightInPoints(excelAnno.titleHeight());
		Cell cell=titleRow.createCell(0);
		cell.setCellValue(excelTitle);
		CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        Font font = workbook.createFont();
        font.setBold(true);
        font.setFontHeightInPoints((short)14);
        style.setFont(font);
		cell.setCellStyle(style);
		rowIndex++;
		Row row=sheet.createRow(rowIndex);
		row.setHeightInPoints(excelAnno.rowHeight());
		int length=excelExportColumnList.size();
		String columnTitle;
		for (int i = 0; i < length; i++) {
			cell=row.createCell(i);
			columnTitle = excelExportColumnList.get(i).getColumnTitle();
			cell.setCellValue(columnTitle);
			if(excelExportColumnList.get(i).getAutoWidth()){
				excelExportColumnList.get(i).setWidth(StringUtils.stringToWordLength(columnTitle)+1);
			}
		}
		CellRangeAddress region = new CellRangeAddress(0, 0, 0, length-1);//合并单元格
		sheet.addMergedRegion(region);
		return ++rowIndex;
	}
	
	@Data
	@Api(value="Excel导出VO实体的列配置", author="unswift", date="2023-07-11", version="1.0.0")
	static class ExcelExportColumn{
		
		@ApiField("字段名称")
		private String fieldName;
		
		@ApiField("字段值类型")
		private Class<?> fieldType;
		
		@ApiField("ExcelColumn注解")
		private ExcelColumn excelColumn;
		
		@ApiField("ApiField注解")
		private ApiField apiFieldAnno;
		
		@ApiField("列顺序")
		private Integer order;
		
		@ApiField("列宽度")
		private Integer width;
		
		@ApiField("是否自适应")
		private Boolean autoWidth;

		public ExcelExportColumn(String fieldName, Class<?> fieldType, ExcelColumn excelColumn, ApiField apiFieldAnno) {
			super();
			this.fieldName = fieldName;
			this.fieldType = fieldType;
			this.excelColumn = excelColumn;
			this.apiFieldAnno=apiFieldAnno;
			this.order = excelColumn.order();
			this.width = excelColumn.width();
			this.autoWidth=this.width==-1;
		}
		
		public String getColumnTitle(){
			if(ObjectUtils.isEmpty(excelColumn.value())){
				if(ObjectUtils.isEmpty(apiFieldAnno) || ObjectUtils.isEmpty(apiFieldAnno.value())){
					return fieldName;
				}else{
					return apiFieldAnno.value();
				}
			}else{
				return excelColumn.value();
			}
		}
	}
	
	@ApiMethod(value="从workbook对象中读取数据并转换为指定实体-全部转换后返回", params = {@ApiField("工作表对象"), @ApiField("需要转换的实体类类型"), @ApiField("表格中标题行，从0开始")}, returns = @ApiField("实体列表"))
	public static <E> List<E> readAll(Workbook workbook, Class<E> modelClass, int titleIndex){
		Sheet sheet=workbook.getSheetAt(0);
		int rowLength=sheet.getPhysicalNumberOfRows();
		if(titleIndex>=rowLength-1) {
			return null;
		}
		List<ExcelImportColumn> excelColumnList = getImportColumnList(modelClass);
		Map<String, ExcelImportColumn> columnMap=excelColumnList.stream().collect(Collectors.toMap(i -> i.getFieldComment(), i -> i));
		Row row=sheet.getRow(titleIndex);
		int cellIndex=row.getPhysicalNumberOfCells();
		Cell cell;
		String title;
		ExcelImportColumn importColumn;
		for (int i = 0; i < cellIndex; i++) {
			cell=row.getCell(i);
			if(ObjectUtils.isEmpty(cell)) {
				continue;
			}
			title=cell.getStringCellValue();
			if(ObjectUtils.isEmpty(title)) {
				continue;
			}
			importColumn = columnMap.get(title);
			if(ObjectUtils.isEmpty(importColumn)) {
				continue;
			}
			importColumn.setOrder(i);
		}
		Map<Integer, ExcelImportColumn> orderColumnMap = columnMap.values().stream().filter(i -> ObjectUtils.isNotEmpty(i.getOrder())).collect(Collectors.toMap(i -> i.getOrder(), i -> i));
		if(ObjectUtils.isEmpty(orderColumnMap)) {
			return null;
		}
		
		
		List<E> resultList=new ArrayList<E>();
		E result;
		String cellValue;
		int first=titleIndex+1;
		Object fieldValue;
		for (int i = first; i < rowLength; i++) {
			row=sheet.getRow(i);
			cellIndex=row.getPhysicalNumberOfCells();
			result=ClassUtils.newInstance(modelClass);
			for (int j = 0; j < cellIndex; j++) {
				importColumn = orderColumnMap.get(j);
				if(ObjectUtils.isEmpty(importColumn)) {
					continue;
				}
				cell=row.getCell(j);
				cellValue=getCellValue(cell);
				if(ObjectUtils.isNotEmpty(cellValue)) {
					continue;
				}
				fieldValue = ClassUtils.stringToBaseJava(cellValue, importColumn.getFieldType());
				ClassUtils.set(result, importColumn.getFieldName(), fieldValue);
			}
			resultList.add(result);
		}
		return resultList;
	}
	@ApiMethod(value="从workbook对象中读取数据并转换为指定实体-分批次执行", params = {@ApiField("工作表对象"), @ApiField("需要转换的实体类类型"), @ApiField("表格中标题行，从0开始")}, returns = @ApiField("实体列表"))
	public static <E> void read(Workbook workbook, Class<E> modelClass, int titleIndex, ExcelImportBatch backBatch){
		Sheet sheet=workbook.getSheetAt(0);
		int rowLength=sheet.getPhysicalNumberOfRows();
		if(titleIndex>=rowLength-1) {
			return ;
		}
		List<ExcelImportColumn> excelColumnList=getImportColumnList(modelClass);
		Map<String, ExcelImportColumn> columnMap=excelColumnList.stream().collect(Collectors.toMap(i -> i.getFieldComment(), i -> i));
		Row row=sheet.getRow(titleIndex);
		int cellIndex=row.getPhysicalNumberOfCells();
		Cell cell;
		String title;
		ExcelImportColumn importColumn;
		for (int i = 0; i < cellIndex; i++) {
			cell=row.getCell(i);
			if(ObjectUtils.isEmpty(cell)) {
				continue;
			}
			title=cell.getStringCellValue();
			if(ObjectUtils.isEmpty(title)) {
				continue;
			}
			importColumn = columnMap.get(title);
			if(ObjectUtils.isEmpty(importColumn)) {
				continue;
			}
			importColumn.setOrder(i);
		}
		for (ExcelImportColumn column : excelColumnList) {
			if(column.getRequired()) {//如果声明为必填，则导入excel必须包含此标题
				ExceptionUtils.empty(column.getOrder(), "import.field.required", column.getFieldComment());
			}
		}
		Map<Integer, ExcelImportColumn> orderColumnMap = columnMap.values().stream().filter(i -> ObjectUtils.isNotEmpty(i.getOrder())).collect(Collectors.toMap(i -> i.getOrder(), i -> i));
		if(ObjectUtils.isEmpty(orderColumnMap)) {
			return ;
		}
		int first=titleIndex+1;
		backBatch.setDataCount(rowLength-first);
		MemoryCache cache=BeanUtils.getBean(MemoryCache.class);
		String cellValue;
		Object fieldValue;
		E result;
		try {
			for (int i = first; i < rowLength; i++) {
				row=sheet.getRow(i);
				cellIndex=row.getLastCellNum();
				result=ClassUtils.newInstance(modelClass);
				for (int j = 0; j < cellIndex; j++) {
					importColumn = orderColumnMap.get(j);
					if(ObjectUtils.isEmpty(importColumn)) {
						continue;
					}
					cell=row.getCell(j);
					cellValue=null;
					if(ObjectUtils.isNotEmpty(cell)) {
						cellValue=getCellValue(cell);
					}
					ExceptionUtils.trueException(importColumn.getRequired() && ObjectUtils.isEmpty(cellValue), "row.field.empty", importColumn.getFieldComment(), i+1);
					if(ObjectUtils.isNotEmpty(cellValue) && importColumn.getUnique()) {
						Integer rowIndex=cache.getHash(importColumn.getFieldName(), cellValue);
						if(ObjectUtils.isNotEmpty(rowIndex)) {
							ExceptionUtils.notEmpty(rowIndex, "row.exists.multiple.value", importColumn.getFieldComment(), cellValue, rowIndex+1, i+1);
						}
						cache.setHash(importColumn.getFieldName(), cellValue, i);//设置缓存
					}
					if(ObjectUtils.isEmpty(cellValue)) {
						continue;
					}
					fieldValue = ClassUtils.stringToBaseJava(cellValue, importColumn.getFieldType());
					ClassUtils.set(result, importColumn.getFieldName(), fieldValue);
				}
				backBatch.validate(result, i);
			}
		} catch(CoreException e) {
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("import.data.error", e, e.getMessage());
		} finally {
			for (ExcelImportColumn column : excelColumnList) {
				if(column.getUnique()) {//如果声明为必填，则导入excel必须包含此标题
					cache.remove(column.getFieldName());//清理缓存
				}
			}
		}
		List<E> resultList=new ArrayList<E>();
		int batchSize=backBatch.getBatchSize();
		int rowIndex=first;
		for (int i = first; i < rowLength; i++) {
			row=sheet.getRow(i);
			cellIndex=row.getLastCellNum();
			result=ClassUtils.newInstance(modelClass);
			for (int j = 0; j < cellIndex; j++) {
				importColumn = orderColumnMap.get(j);
				if(ObjectUtils.isEmpty(importColumn)) {
					continue;
				}
				cell=row.getCell(j);
				if(ObjectUtils.isEmpty(cell)) {
					continue;
				}
				cellValue=getCellValue(cell);
				if(ObjectUtils.isEmpty(cellValue)) {
					continue;
				}
				fieldValue = ClassUtils.stringToBaseJava(cellValue, importColumn.getFieldType());
				ClassUtils.set(result, importColumn.getFieldName(), fieldValue);
			}
			resultList.add(result);
			if(resultList.size()>=batchSize) {
				backBatch.handleBatch(resultList, rowIndex);
				resultList=new ArrayList<E>();
				rowIndex=i;
			}
		}
		if(ObjectUtils.isNotEmpty(resultList)) {
			backBatch.handleBatch(resultList, rowIndex);
			resultList=null;
		}
	}
	
	private static String getCellValue(Cell cell) {
		CellType cellType = cell.getCellType();
		if (cellType == CellType.STRING) {
            return cell.getStringCellValue();
        } else if (cellType == CellType.NUMERIC) {
            if (DateUtil.isCellDateFormatted(cell)) {
                Date value = cell.getDateCellValue();
                return DateUtils.format(value, "yyyy-MM-dd HH:mm:ss");
            } else {
                double numericValue = cell.getNumericCellValue();
                return NumberUtils.format(numericValue, "###");
            }
        } else if (cellType == CellType.BOOLEAN) {
            boolean value = cell.getBooleanCellValue();
            return String.valueOf(value);
        }else {
        	return null;
        }
	}
	
	@ApiMethod(value="获取导入的列对象集合", params=@ApiField("导入实体模板"), returns=@ApiField("列对象集合"))
	private static List<ExcelImportColumn> getImportColumnList(Class<?> excelModel){
		List<Field> fieldList=ClassUtils.getFieldList(excelModel).stream().filter(f -> ObjectUtils.isNotEmpty(f.getAnnotation(ExcelColumn.class))).collect(Collectors.toList());
		List<ExcelImportColumn> excelColumnList=new ArrayList<ExcelImportColumn>();
		ExcelImportColumn importField;
		ExcelColumn excelAnno;
		for (Field field : fieldList) {
			excelAnno = field.getAnnotation(ExcelColumn.class);
			importField = new ExcelImportColumn(field.getName(), excelAnno.value(), field.getType());
			importField.setUnique(excelAnno.unique());
			importField.setRequired(excelAnno.required());
			excelColumnList.add(importField);
		}
		return excelColumnList;
	}
	
	@Data
	@Api(value="Excel导入VO实体的列配置", author="unswift", date="2024-01-03", version="1.0.0")
	static class ExcelImportColumn{
		
		@ApiField("字段名称")
		private String fieldName;
		
		@ApiField("字段描述")
		private String fieldComment;
		
		@ApiField("字段值类型")
		private Class<?> fieldType;
		
		@ApiField("列顺序")
		private Integer order;
		
		@ApiField("唯一列")
		private Boolean unique;
		
		@ApiField("必须")
		private Boolean required;

		public ExcelImportColumn(String fieldName, String fieldComment, Class<?> fieldType) {
			this.fieldName = fieldName;
			this.fieldComment = fieldComment;
			this.fieldType = fieldType;
		}
		
	}
	
	@Data
	@Api(value="Excel导入批次处理", author="unswift", date="2024-01-09", version="1.0.0")
	public abstract static class ExcelImportBatch{
		
		@ApiField("批次大小")
		private int batchSize;
		@ApiField("导入数据总数量")
		private int dataCount;

		public ExcelImportBatch(int batchSize) {
			super();
			this.batchSize = batchSize;
		}
		
		@ApiMethod(value="验证导入行数据", params = {@ApiField("行数据"), @ApiField("数据在excel中的行次")})
		public abstract void validate(Object data, int rowIndex);
		
		@ApiMethod(value="导入数据批量处理，批次数据根据nocos配置确定批次大小", params = {@ApiField("批次数据"), @ApiField("此列表在excel中的开始行次（从零开始）")})
		public abstract void handleBatch(List<?> dataList, int startRowIndex);
	}
}
